﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Tsanie.DmPoster.Utils;
using Tsanie.DmPoster.Models;
using System.Reflection;
using System.Xml;
using System.IO;
using System.IO.Compression;
using System.Web;
using System.Threading;
using System.Runtime.InteropServices;

namespace Tsanie.DmPoster {

    public enum PostState { None, PreSending, Sending, Paused, Stopped, Error }
    public enum Read { None = 0, CommentPool = 1, Desc = 2 }
    public delegate void Func<T>(T value, int n);

    public partial class MainForm : Form {
        //[DllImport("uxtheme.dll", CharSet = CharSet.Unicode)]
        //public extern static int SetWindowTheme(IntPtr hWnd, string pszSubAppName, string pszSubIdList);

        #region - 私有字段 -
        // 弹幕容器
        internal CommentManager<BiliComment> _comments;
        // 当前最大ID
        private int _maxId = 0;
        // 弹幕是否发生修改
        private bool _changed = false;
        // 弹幕文件地址
        private string _dmFile = null;
        // 弹幕发送状态
        private PostState _postState = PostState.None;
        // 弹幕网络助手
        private Net _net;
        // 选中的索引集合
        internal int[] _selected = null;
        #endregion

        public MainForm() {
            InitializeComponent();
            Config.LoadConfig();
            InitializeVars();

            //SetWindowTheme(gridComments.Handle, "explorer", null);
        }

        private void InitializeVars() {
            this.Text = "无标题 - " + Config.c_AppCaption;
            _net = new Net(this);
            _comments = new CommentManager<BiliComment>(
                new Event.PropertyHandler(CommentChanged));
            this.toolComboPool.SelectedIndex = 0;
            this.columnID.ValueType = typeof(string);
            this.columnPlayTime.ValueType = typeof(float);
            this.columnFontsize.ValueType = typeof(int);
        }
        private void CheckCookie(object sender, EventArgs e) {
            statusUser.Click -= new EventHandler(CheckCookie);
            statusUser.Text = "检查权限...";
            statusUser.BackColor = Color.FromArgb(255, 224, 192);
            _net.CheckCookie(Config.m_Cookie, (msg) => {
                statusMessage.Text = msg;
            }, (level) => {
                Config.m_Level = level;
                if (level != Level.Guest) {
                    statusUser.Image =
                        global::Tsanie.DmPoster.Properties.Resources.logined;
                } else {
                    if (level == Level.Guest)
                        toolTextStep.Text = "10.2";
                    else if (level == Level.Member)
                        toolTextStep.Text = "5.2";
                }
                statusUser.BackColor = Color.Empty;
                statusUser.Text = StringUtil.StringFromLevel(level);
                EnableToolStrip(true);
            }, (ex) => {
                statusUser.Text = "游客";
                statusUser.ToolTipText = "点击此处重新验证权限。";
                MessageBox.Show(this, ex.Message, "错误",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                statusUser.Click += new EventHandler(CheckCookie);
            });
        }
        private void EnableToolStrip(bool enable) {
            menuOpreate.Enabled = enable;
            menuComment.Enabled = enable;
            menuMulti.Enabled = enable;
            toolButtonAdd.Enabled = enable;
            toolButtonOpen.Enabled = enable;
            toolButtonSave.Enabled = enable;
            toolButtonPost.Enabled = enable;
            toolButtonStop.Enabled = !enable;
            toolButtonUpload.Enabled = false;
            menuUpload.Enabled = false;
            toolComboPool.Enabled = false;
            toolButtonPlayer.Enabled = enable;
            toolTextId.Enabled = enable;
            toolButtonDownload.Enabled = enable;
            gridComments.Enabled = enable;
            if (enable) {
                gridComments.Width = 0;
                // 字幕君以上权限
                if (Config.m_Level >= Level.Commenter) {
                    toolButtonUpload.Enabled = true;
                    menuUpload.Enabled = true;
                    toolComboPool.Enabled = true;
                }
                float step = float.Parse(toolTextStep.Text);
                if (Config.m_Level == Level.Guest)
                    toolTextStep.Text = "10.0";
                else if (Config.m_Level == Level.Member)
                    toolTextStep.Text = "5.0";
                else if (Config.m_Level >= Level.Commenter)
                    toolTextStep.Text = "1.0";

            }
        }
        private void CommentChanged(BiliComment comm, BiliProperty prop) {
            if (PlayerForm._player != null)
                PlayerForm._player.InvaliteTexture(comm);
            // 新添加的弹幕不处理UI
            if (comm.Id > _maxId)
                return;
            if (prop == BiliProperty.PlayTime) {
                _comments.Order(comm);
                //MessageBox.Show("ordered");
            }
        }
        private void Changed(bool changed) {
            if (_changed == changed)
                return;
            _changed = changed;
            string caption = (_dmFile == null ? "未命名"
                : _dmFile.Substring(_dmFile.LastIndexOf('\\') + 1))
                + " - " + Config.c_AppCaption;
            if (changed) {
                this.Text = caption + " *";
            } else {
                this.Text = caption;
                foreach (DataGridViewRow row in gridComments.Rows) {
                    ChangeRow(row, false);
                }
            }
        }
        private void ChangeRow(DataGridViewRow row, bool changed) {
            if (changed) {
                row.DefaultCellStyle.BackColor = Color.FromArgb(255, 208, 208);
                int color = _comments[row.Cells[0].Value.ToString()].Color;
                row.Cells[2].Style.BackColor = Color.FromArgb(-16777216 | color);
                row.Cells[2].Style.ForeColor = Color.FromArgb(-16777216 | (color ^ 0xffffff));
            } else {
                if (row.DefaultCellStyle.BackColor != Color.Empty)
                    row.DefaultCellStyle.BackColor = Color.Empty;
            }
        }
        private void AddComment(int index, BiliComment comm) {
            CommentForm.ShowCommentForm(comm, m => {
                index = Edited(index, m);
                statusMessage.Text = "当前 " + _comments.Count + " 条弹幕。";
            }, null);
        }
        internal int Added(int index, BiliComment comm) {
            // 添加新项
            object[] values = new object[]{
                comm.Id,
                comm.PlayTime,
                StringUtil.StringFromColorInt(comm.Color),
                comm.Fontsize,
                null,
                comm.Message
                };
            if (index < 0 || index >= gridComments.Rows.Count) {
                index = gridComments.Rows.Add(values);
            } else {
                gridComments.Rows.Insert(index, values);
            }
            _comments.Add(comm);
            _maxId++;
            Changed(true);
            return index;
        }
        internal int Edited(int index, BiliComment comm) {
            // 判断是否存在
            foreach (DataGridViewRow row in gridComments.Rows) {
                if (comm.Id.ToString() == row.Cells[0].Value.ToString()) {
                    // 找到
                    row.Cells[1].Value = comm.PlayTime;
                    row.Cells[2].Value = StringUtil.StringFromColorInt(comm.Color);
                    row.Cells[3].Value = comm.Fontsize;
                    row.Cells[5].Value = comm.Message;
                    Changed(true);
                    ChangeRow(row, true);
                    gridComments.CurrentCell = row.Cells[1];
                    return row.Index;
                }
            }
            // 不存在则添加
            int rtn = Added(index, comm);
            DataGridViewRow r = gridComments.Rows[rtn];
            ChangeRow(r, true);
            gridComments.CurrentCell = r.Cells[1];
            return rtn;
        }
        internal int CurrentRowIndex() {
            DataGridViewRow row = gridComments.CurrentRow;
            if (row == null)
                return -1;
            return row.Index + 1;
        }
        internal bool IsSelected(int id) {
            if (_selected == null)
                return false;
            for (int i = 0; i < _selected.Length; i++) {
                if (_selected[i] == id)
                    return true;
            }
            return false;
        }
        internal void Select(int index) {
            if (index < 0 || index >= gridComments.RowCount)
                return;
            gridComments.CurrentCell = gridComments.Rows[index].Cells[1];
        }
        private bool SaveChange() {
            // 判断是否有改动
            if (_changed) {
                DialogResult dr = MessageBox.Show(this, "弹幕已改变，是否保存？", "保存",
                    MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
                if (dr == System.Windows.Forms.DialogResult.Cancel)
                    return false;
                else if (dr == System.Windows.Forms.DialogResult.Yes)
                    if (!Save())
                        return false;
            }
            return true;
        }
        private bool Save() {
            if (string.IsNullOrEmpty(_dmFile)) {
                if (saveDialog.ShowDialog(this) != System.Windows.Forms.DialogResult.OK)
                    return false;
                SaveFile(saveDialog.FileName);
            } else {
                SaveFile(_dmFile);
            }
            Changed(false);
            return true;
        }
        private void SaveFile(string file) {
            _dmFile = file;
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Encoding = Encoding.UTF8;
            settings.Indent = true;
            XmlWriter writer = XmlWriter.Create(file, settings);
            writer.WriteStartElement("information");
            float offset = float.Parse(toolTextOffset.Text);

            _comments.ForEach(m => {
                writer.WriteStartElement("data");
                writer.WriteElementString("playTime", m.PlayTime.ToString());
                writer.WriteStartElement("message");
                writer.WriteAttributeString("fontsize", m.Fontsize.ToString());
                writer.WriteAttributeString("color", m.Color.ToString());
                writer.WriteAttributeString("mode", m.Mode.ToString());
                writer.WriteCData(m.Message);
                writer.WriteEndElement();
                writer.WriteElementString("times", m.Date.ToString("yyyy-MM-dd HH:mm:ss"));
                writer.WriteEndElement();
                return true;
            });

            writer.WriteEndElement();
            writer.Flush();
            writer.Close();
            statusMessage.Text = "保存弹幕文件成功！";
            Changed(false);
        }
        private void OpenFile(string file) {
            ReadXml(new FileStream(file, FileMode.Open, FileAccess.Read), Read.None);
            _dmFile = file;
            Changed(false);
        }
        private void OpenText(string file) {
            StreamReader sr = new StreamReader(file, Encoding.UTF32);
            string line = sr.ReadLine();
            int y = int.Parse(line);
            StringBuilder sb = new StringBuilder(256);
            bool notf = false;
            int lines = 0;
            // 开始
            for (int ln = 0; ln < y; ln++) {
                line = sr.ReadLine();
                if (line == null)
                    break;
                if (line.EndsWith("█")) {
                    line = line.Substring(0, line.Length - 1);
                }
                if (notf) {
                    for (int i = 0; i < ln; i++) {
                        sb.Append("/n");
                    }
                    notf = false;
                }
                sb.Append(line + "/n");
                if ((lines > 0 && ln % lines == 0) || (line.Length + sb.Length > 240)) {
                    for (int i = ln + 1; i < y; i++) {
                        sb.Append("/n");
                    }
                    // 添加弹幕
                    BiliComment cmt = new BiliComment();
                    cmt.Color = Config.m_color;
                    cmt.Date = DateTime.Now;
                    cmt.Fontsize = Config.m_fontsize;
                    cmt.Message = sb.ToString();
                    cmt.Mode = Config.m_mode;
                    cmt.PlayTime = Config.m_playTime;
                    Added(-1, cmt);
                    sb.Remove(0, sb.Length);
                    notf = true;
                }
            }
            if (sb.Length > 0) {
                BiliComment cmt = new BiliComment();
                cmt.Color = Config.m_color;
                cmt.Date = DateTime.Now;
                cmt.Fontsize = Config.m_fontsize;
                cmt.Message = sb.ToString();
                cmt.Mode = Config.m_mode;
                cmt.PlayTime = Config.m_playTime;
                Added(-1, cmt);
            }

            statusMessage.Text = "导入完毕。";
            sr.Close();
            sr.Dispose();
        }
        private void ReadXml(Stream stream, Read param) {
            EnableToolStrip(false);
            gridComments.Rows.Clear();
            _comments.Clear();
            ReadXml(stream, (comm) => {
                Added(-1, comm);
            }, param, () => {
                statusMessage.Text = "弹幕加载完毕...一共 " + _comments.Count + " 条。";
                EnableToolStrip(true);
                gridComments.Focus();
            }, (ex) => {
                MessageBox.Show(this, ex.Message, "解码",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                statusMessage.Text = ex.Message;
                EnableToolStrip(true);
                gridComments.Focus();
            });
        }
        private void ReadXml(Stream stream, Action<BiliComment> exec, Read param,
            MethodInvoker complete, Action<Exception> errHandler) {
            // 最大2M的xml文件
            byte[] bs = new byte[2097152];
            byte[] buffer = new byte[512];
            int pt = 0;
            int length = 0;
            try {
                while ((length = stream.Read(buffer, 0, 512)) > 0) {
                    for (int i = 0; i < length; i++) {
                        if (buffer[i] >= 32 || buffer[i] == 10 || buffer[i] == 13) {
                            bs[pt++] = buffer[i];
                        }
                    }
                }
                XmlTextReader reader = new XmlTextReader(new MemoryStream(bs, 0, pt));
                BiliComment comm;
                while (reader.Read()) {
                    if (reader.NodeType == XmlNodeType.Element) {
                        try {
                            if (reader.Name == "data") {
                                reader.ReadStartElement("data");
                                float playTime = float.Parse(
                                    reader.ReadElementString("playTime"));
                                while (reader.Name != "message")
                                    reader.Read();
                                int fontsize = int.Parse(reader.GetAttribute("fontsize"));
                                int color = int.Parse(reader.GetAttribute("color"));
                                int mode = int.Parse(reader.GetAttribute("mode"));
                                string message = reader.ReadString();
                                reader.ReadEndElement();
                                DateTime date = StringUtil.DateFormString(
                                    reader.ReadElementString("times"));
                                if (mode == 7) {
                                    comm = new BiliPosComment();
                                } else {
                                    comm = new BiliComment();
                                }
                                comm.PlayTime = playTime;
                                comm.Fontsize = fontsize;
                                comm.Color = color;
                                comm.Date = date;
                                comm.Mode = mode;
                                comm.Message = message;
                                // 执行委托
                                exec(comm);
                            } else if (reader.Name == "d") {
                                string[] vs = reader.GetAttribute("p").Split(',');
                                float playTime = float.Parse(vs[0]);
                                int fontsize = int.Parse(vs[2]);
                                int color = int.Parse(vs[3]);
                                DateTime date = StringUtil.DateFromLong(long.Parse(vs[4]));
                                int mode = int.Parse(vs[1]);
                                string user = vs[6];
                                string message = reader.ReadString();
                                if (mode == 7) {
                                    comm = new BiliPosComment();
                                } else {
                                    comm = new BiliComment();
                                }
                                comm.PlayTime = playTime;
                                comm.Fontsize = fontsize;
                                comm.Color = color;
                                comm.Date = date;
                                comm.Mode = mode;
                                comm.User = user;
                                comm.Message = message;
                                if (((param & Read.CommentPool) == Read.CommentPool)
                                    && vs[5] != "1")
                                    continue;
                                // 执行委托
                                exec(comm);
                            }
                        } catch (Exception ex) {
                            MessageBox.Show(this, "格式错误：" + ex.Message, "解析",
                                MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                    }
                }
                reader.Close();
                if (complete != null)
                    complete();
            } catch (Exception ex) {
                if (errHandler != null)
                    errHandler(ex);
                return;
            }
        }
        private void EnumSelected(Func<DataGridViewRow> exec, MethodInvoker complete) {
            if (exec == null)
                return;
            int count = gridComments.SelectedRows.Count;
            if (count > 0) {
                for (int i = count - 1; i >= 0; i--) {
                    exec(gridComments.SelectedRows[i], i);
                }
                Changed(true);
                if (complete != null)
                    complete();
            }
        }

        private void statusStrip_Resize(object sender, EventArgs e) {
            statusMessage.Width = this.Width - 225;
        }
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e) {
            // 判断是否有改动
            if (!SaveChange()) {
                e.Cancel = true;
                return;
            }
        }
        private void MainForm_FormClosed(object sender, FormClosedEventArgs e) {
            if (PlayerForm._player != null) {
                PlayerForm._player.Invoke(new MethodInvoker(() => {
                    PlayerForm._player.Close();
                }));
            }
        }
        private void MainForm_Shown(object sender, EventArgs e) {
            if (!string.IsNullOrEmpty(Config.m_Cookie)) {
                CheckCookie(null, null);
            }
        }

        private void Login_Click(object sender, EventArgs e) {
            if (LoginForm.ShowLogin(this)) {
                CheckCookie(null, null);
            }
        }
        private void Open_Click(object sender, EventArgs e) {
            // 判断是否有改动
            if (!SaveChange()) {
                return;
            }
            if (openDialog.ShowDialog(this) == System.Windows.Forms.DialogResult.OK) {
                if (openDialog.FileName.EndsWith(".txt"))
                    OpenText(openDialog.FileName);
                else
                    OpenFile(openDialog.FileName);
            }
        }
        private void Save_Click(object sender, EventArgs e) {
            if (_changed)
                Save();
        }
        private void SaveAs_Click(object sender, EventArgs e) {
            if (saveDialog.ShowDialog(this) != System.Windows.Forms.DialogResult.OK)
                return;
            SaveFile(saveDialog.FileName);
            Changed(false);
        }
        private void Download_Click(object sender, EventArgs e) {
            string av = toolTextId.Text.Trim();
            if (string.IsNullOrEmpty(av)) {
                MessageBox.Show(this, "Av/Vid不可为空！", "ID",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                toolTextId.Focus();
                return;
            }
            bool pool = false;
            DialogResult dr = MessageBox.Show(this, "是否只下载字幕池弹幕？", "下载",
                MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
            if (dr == System.Windows.Forms.DialogResult.Cancel)
                return;
            else if (dr == System.Windows.Forms.DialogResult.Yes)
                pool = true;
            _net.Download(av, (msg) => {
                statusMessage.Text = msg;
            }, (stream) => {
                ReadXml(new DeflateStream(stream, CompressionMode.Decompress),
                    (pool ? Read.CommentPool : Read.None));
            });
        }
        private void Upload_Click(object sender, EventArgs e) {
            if (MessageBox.Show(this, "是否确定上传？", "上传xml",
                MessageBoxButtons.YesNo, MessageBoxIcon.Question)
                == System.Windows.Forms.DialogResult.No) {
                statusMessage.Text = "用户取消上传。";
                return;
            }
            string av = toolTextId.Text.Trim();
            if (string.IsNullOrEmpty(av)) {
                MessageBox.Show(this, "Av/Vid不可为空！", "ID",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                toolTextId.Focus();
                return;
            }
            if (_comments.Count == 0) {
                MessageBox.Show(this, "无弹幕可供上传！", "上传xml",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                statusMessage.Text = "请插入一些弹幕。";
                return;
            }
            DialogResult dr = MessageBox.Show(this, "是否上传所有弹幕？", "上传xml",
                MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
            if (dr == System.Windows.Forms.DialogResult.Cancel)
                return;
            bool uploadAll = (dr == System.Windows.Forms.DialogResult.Yes);
            if (!uploadAll && gridComments.SelectedRows.Count == 0) {
                MessageBox.Show(this, "请先选择要上传的弹幕！", "上传xml",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                statusMessage.Text = "请先选择要上传的弹幕。";
                return;
            }
            if (uploadAll) {
                _net.Upload(av, float.Parse(toolTextOffset.Text), _comments.Copy(),
                    (msg) => {
                        statusMessage.Text = msg;
                    });
            } else {
                BiliComment[] comments = new BiliComment[gridComments.SelectedRows.Count];
                int index = 0;
                for (int i = gridComments.SelectedRows.Count - 1; i >= 0; i--) {
                    comments[index++] = _comments[
                        gridComments.SelectedRows[i].Cells[0].Value.ToString()];
                }
                _net.Upload(av, float.Parse(toolTextOffset.Text), comments,
                    (msg) => {
                        statusMessage.Text = msg;
                    });
            }
        }
        private void Exit_Click(object sender, EventArgs e) {
            this.Close();
        }
        private void Add_Click(object sender, EventArgs e) {
            AddComment(-1, null);
        }
        private void Insert_Click(object sender, EventArgs e) {
            int index = -1;
            if (gridComments.CurrentRow != null)
                index = gridComments.CurrentRow.Index;
            AddComment(index, null);
        }
        private void Edit_Click(object sender, EventArgs e) {
            DataGridViewRow row = gridComments.CurrentRow;
            if (row == null)
                return;
            BiliComment comm = _comments[row.Cells[0].Value.ToString()];
            CommentForm.ShowCommentForm(comm,
                (m) => {
                    if (m != comm) {
                        // 改为新弹幕
                        _comments.Remove(comm);
                        _comments.Add(m);
                        row.Cells[0].Value = m.Id.ToString();
                    }
                    row.Cells[1].Value = m.PlayTime;
                    row.Cells[2].Value = StringUtil.StringFromColorInt(m.Color);
                    row.Cells[3].Value = m.Fontsize;
                    row.Cells[5].Value = m.Message;
                    ChangeRow(row, true);
                    Changed(true);
                }, null);
        }
        private void Spect_Click(object sender, EventArgs e) {
            DataGridViewRow row = gridComments.CurrentRow;
            if (row == null)
                return;
            BiliComment comm = _comments[row.Cells[0].Value.ToString()];
            if (comm.Mode == 7) { // comm is BiliPosComment
                MessageBox.Show(this, "定位弹幕无法分割！", "分割弹幕",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
            int index = row.Index;
            gridComments.Rows.Remove(row);
            _comments.Remove(comm);
            string[] lines = comm.Message.Split(new string[] { "/n" },
                StringSplitOptions.None);
            for (int i = lines.Length - 1; i >= 0; i--) {
                if (string.IsNullOrEmpty(lines[i]))
                    continue;
                BiliComment m = comm.Clone();
                string s = "";
                for (int j = 0; j < i; j++)
                    s += "/n";
                s += lines[i];
                for (int j = i; j < lines.Length - 1; j++)
                    s += "/n";
                m.Message = s;
                ChangeRow(gridComments.Rows[Added(index, m)], true);
            }
            Select(index);
        }
        private void Remove_Click(object sender, EventArgs e) {
            bool remove = false;
            for (int i = gridComments.SelectedRows.Count - 1; i >= 0; i--) {
                DataGridViewRow row = gridComments.SelectedRows[i];
                gridComments.Rows.Remove(row);
                remove |= _comments.Remove(row.Cells[0].Value.ToString());
            }
            if (remove)
                Changed(true);
        }
        private void Copy_Click(object sender, EventArgs e) {
            StringBuilder builder = new StringBuilder();
            for (int i = gridComments.SelectedRows.Count - 1; i >= 0; i--) {
                BiliComment comm =
                    _comments[gridComments.SelectedRows[i].Cells[0].Value.ToString()];
                builder.AppendLine("<data>");
                builder.AppendLine("  <playTime>" + comm.PlayTime + "</playTime>");
                builder.AppendLine("  <message fontsize=\"" + comm.Fontsize
                    + "\" color=\"" + comm.Color + "\" mode=\"" + comm.Mode + "\">"
                    + HttpUtility.HtmlEncode(comm.Message) + "</message>");
                builder.AppendLine("  <times>" + comm.Date.ToString("yyyy-MM-dd HH:mm:ss")
                    + "</times>");
                builder.AppendLine("</data>");
            }
            if (builder.Length > 0) {
                Clipboard.SetText(builder.ToString());
                statusMessage.Text = "已复制到粘贴板。";
            }
        }
        private void Paste_Click(object sender, EventArgs e) {
            string str = Clipboard.GetText();
            if (string.IsNullOrEmpty(str)) {
                return;
            }
            MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes("<information>"
                + str + "</information>"));
            // 粘贴位置
            int index = -2;
            if (gridComments.CurrentRow != null) {
                index = gridComments.CurrentRow.Index;
            }
            ReadXml(ms, (comm) => {
                index = Added(index + 1, comm);
                DataGridViewRow row = gridComments.Rows[index];
                ChangeRow(row, true);
            }, Read.None, () => {
                if (index >= 0) {
                    gridComments.CurrentCell = gridComments.Rows[index].Cells[1];
                    statusMessage.Text = "成功粘贴，当前 " + _comments.Count + " 条弹幕。";
                }
            }, (ex) => {
                MessageBox.Show(this, ex.Message, "粘贴", MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            });
        }
        private void PasteEdit_Click(object sender, EventArgs e) {
        }
        private void MoveUp_Click(object sender, EventArgs e) {
            DataGridViewRow row = gridComments.CurrentRow;
            if (row == null)
                return;
            int index = row.Index;
            if (index == 0) {
                MessageBox.Show(this, "无法再往上移动！", "移动", MessageBoxButtons.OK,
                    MessageBoxIcon.Warning);
                return;
            }
            BiliComment comm = _comments[row.Cells[0].Value.ToString()];
            BiliComment cmt = _comments[gridComments[0, index - 1].Value.ToString()];
            comm.Date = cmt.Date.Subtract(new TimeSpan(0, 0, 0, 0, 1));
            _comments.Order(comm);
            gridComments.Rows.RemoveAt(index);
            gridComments.Rows.Insert(index - 1, row);
            gridComments.CurrentCell = row.Cells[1];
            ChangeRow(row, true);
            Changed(true);
        }
        private void MoveDown_Click(object sender, EventArgs e) {
            DataGridViewRow row = gridComments.CurrentRow;
            if (row == null)
                return;
            int index = row.Index;
            if (index == gridComments.RowCount - 1) {
                MessageBox.Show(this, "无法再往下移动！", "移动", MessageBoxButtons.OK,
                    MessageBoxIcon.Warning);
                return;
            }
            BiliComment comm = _comments[row.Cells[0].Value.ToString()];
            BiliComment cmt = _comments[gridComments[0, index - 1].Value.ToString()];
            comm.Date = cmt.Date.Add(new TimeSpan(0, 0, 0, 0, 1));
            _comments.Order(comm);
            gridComments.Rows.RemoveAt(index);
            gridComments.Rows.Insert(index + 1, row);
            gridComments.CurrentCell = row.Cells[1];
            ChangeRow(row, true);
            Changed(true);
        }
        private void Select_Click(object sender, EventArgs e) {
            List<string> selected = new List<string>();
            _comments.ForEach((comm) => {
                if (comm.User != null && !selected.Contains(comm.User))
                    selected.Add(comm.User);
                return true;
            });
            List<string> list;
            if (SelectForm.ShowDialog(this, selected, out list) == DialogResult.OK) {
                for (int i = 0; i < gridComments.RowCount; i++) {
                    DataGridViewRow row = gridComments.Rows[i];
                    bool sel = false;
                    BiliComment comm = _comments[row.Cells[0].Value.ToString()];
                    if (comm != null) {
                        if (list.Contains(comm.User)) {
                            sel = true;
                        }
                    }
                    row.Selected = sel;
                }
            }
        }
        private void Player_Click(object sender, EventArgs e) {
            if (PlayerForm._player != null) {
                NativeMethods.SetForegroundWindow(PlayerForm._player.Handle);
            } else {
                if (openDialogPlayer.ShowDialog(this) == DialogResult.OK) {
                    PlayerForm.ShowPlayer(openDialogPlayer.FileName);
                }
            }
        }
        private void InsertStart_Click(object sender, EventArgs e) {
            string str = InputForm.ShowInput(this, "输入想插入的内容", "插入到弹幕之前");
            if (str != null) {
                EnumSelected((row, n) => {
                    try {
                        BiliComment comm = _comments[row.Cells[0].Value.ToString()];
                        comm.Message = str + comm.Message;
                        row.Cells[5].Value = comm.Message;
                        ChangeRow(row, true);
                    } catch (Exception ex) {
                        MessageBox.Show(this, ex.Message, "错误", MessageBoxButtons.OK,
                            MessageBoxIcon.Error);
                    }
                }, () => {
                    statusMessage.Text = "插入完毕！";
                });
            }
        }
        private void InsertEnd_Click(object sender, EventArgs e) {
            string str = InputForm.ShowInput(this, "输入想插入的内容", "插入到弹幕之后");
            if (str != null) {
                EnumSelected((row, n) => {
                    try {
                        BiliComment comm = _comments[row.Cells[0].Value.ToString()];
                        comm.Message += str;
                        row.Cells[5].Value = comm.Message;
                        ChangeRow(row, true);
                    } catch (Exception ex) {
                        MessageBox.Show(this, ex.Message, "错误", MessageBoxButtons.OK,
                            MessageBoxIcon.Error);
                    }
                }, () => {
                    statusMessage.Text = "插入完毕！";
                });
            }
        }
        private void EditFontsize_Click(object sender, EventArgs e) {
            string str = InputForm.ShowInput(this, "输入要更改的字号", "字号");
            int fontsize;
            if (str != null && int.TryParse(str, out fontsize)) {
                EnumSelected((row, n) => {
                    BiliComment comm = _comments[row.Cells[0].Value.ToString()];
                    comm.Fontsize = fontsize;
                    row.Cells[3].Value = comm.Fontsize;
                    ChangeRow(row, true);
                }, () => {
                    statusMessage.Text = "修改字号完毕！";
                });
            }
        }
        private void EditColorConstant_Click(object sender, EventArgs e) {
            string str = InputForm.ShowInput(this, "输入要更改的颜色（#十六进制、或十进制）",
                "颜色");
            if (str != null) {
                int color = StringUtil.IntColorFromString(str);
                EnumSelected((row, n) => {
                    BiliComment comm = _comments[row.Cells[0].Value.ToString()];
                    comm.Color = color;
                    row.Cells[2].Value = StringUtil.StringFromColorInt(color);
                    ChangeRow(row, true);
                }, () => {
                    statusMessage.Text = "修改颜色完毕！";
                });
            }
        }
        private void EditColorGradual_Click(object sender, EventArgs e) {
            Color c1, c2;
            if (colorChooser.ShowDialog(this) == System.Windows.Forms.DialogResult.OK)
                c1 = colorChooser.Color;
            else
                return;
            if (colorChooser.ShowDialog(this) == System.Windows.Forms.DialogResult.OK)
                c2 = colorChooser.Color;
            else
                return;
            int r1 = c1.R, r2 = c2.R;
            int g1 = c1.G, g2 = c2.G;
            int b1 = c1.B, b2 = c2.B;
            int n = 0;
            int count = gridComments.SelectedRows.Count;
            EnumSelected((row, i) => {
                int color = (r1 + (r2 - r1) * n / (count - 1)) << 16
                    | (g1 + (g2 - g1) * n / (count - 1)) << 8
                    | (b1 + (b2 - b1) * n / (count - 1));
                BiliComment comm = _comments[row.Cells[0].Value.ToString()];
                comm.Color = color;
                row.Cells[2].Value = StringUtil.StringFromColorInt(color);
                ChangeRow(row, true);
                n++;
            }, () => {
                statusMessage.Text = "修改颜色完毕！";
            });
        }
        private void EditTimeConstant_Click(object sender, EventArgs e) {
            string str = InputForm.ShowInput(this, "输入要更改的时间", "时间");
            float time;
            if (str != null && float.TryParse(str, out time)) {
                EnumSelected((row, n) => {
                    BiliComment comm = _comments[row.Cells[0].Value.ToString()];
                    comm.PlayTime = time;
                    row.Cells[1].Value = comm.PlayTime;
                    ChangeRow(row, true);
                }, () => {
                    statusMessage.Text = "修改时间完毕！";
                });
            }
        }
        private void EditTimeAdd_Click(object sender, EventArgs e) {
            string str = InputForm.ShowInput(this, "输入要增加的时间", "时间");
            float time;
            if (str != null && float.TryParse(str, out time)) {
                EnumSelected((row, n) => {
                    BiliComment comm = _comments[row.Cells[0].Value.ToString()];
                    comm.PlayTime += time;
                    comm.PlayTime = (float)Math.Round(comm.PlayTime * 10) / 10f;
                    row.Cells[1].Value = comm.PlayTime;
                    ChangeRow(row, true);
                }, () => {
                    statusMessage.Text = "修改时间完毕！";
                });
            }
        }
        private void EditTimeStep_Click(object sender, EventArgs e) {
            string strStart = InputForm.ShowInput(this, "输入起始时间：", "时间");
            if (strStart == null)
                return;
            float start;
            string strTime = InputForm.ShowInput(this, "输入增量：", "时间");
            if (strTime == null)
                return;
            float step;
            if (float.TryParse(strStart, out start)
                && float.TryParse(strTime, out step)) {
                int index = 0;
                EnumSelected((row, n) => {
                    BiliComment comm = _comments[row.Cells[0].Value.ToString()];
                    comm.PlayTime = start + index * step;
                    comm.PlayTime = (float)Math.Round(comm.PlayTime * 10) / 10f;
                    row.Cells[1].Value = comm.PlayTime;
                    ChangeRow(row, true);
                    index++;
                }, () => {
                    statusMessage.Text = "修改时间完毕！";
                });
            }
        }
        private void EditMode_Click(object sender, EventArgs e) {
            string str = InputForm.ShowInput(this, "输入更改的模式：（\n1 - 滚动模式，4 - 底部固定，5 - 顶部固定，6 - 逆向弹幕，7 - 定位弹幕）", "模式");
            int mode;
            if (str != null && int.TryParse(str, out mode)) {
                if (mode != 1 && mode < 4 && mode > 7) {
                    MessageBox.Show(this, "模式不在预期值范围之内！", "更改模式",
                        MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }
                EnumSelected((row, n) => {
                    BiliComment comm = _comments[row.Cells[0].Value.ToString()];
                    comm.Mode = mode;
                }, () => {
                    statusMessage.Text = "修改模式完毕！";
                });
            }
        }
        private void EditPosAlpha_Click(object sender, EventArgs e) {
            string str = InputForm.ShowInput(this, "输入透明度变化（格式“a1-a2”，a1和a2为0.0~1.0之间的小数）：", "透明度");
            if (str != null) {
                string[] astr = str.Split('-');
                float a1 = float.Parse(astr[0]);
                float a2 = float.Parse(astr[1]);
                if ((a1 < 0 || a1 > 1) || (a2 < 0 || a2 > 1)) {
                    MessageBox.Show(this, "透明度不在预期值范围之内！", "更改透明度",
                        MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }
                EnumSelected((row, n) => {
                    BiliComment comm = _comments[row.Cells[0].Value.ToString()];
                    if (comm is BiliPosComment) {
                        BiliPosComment pos = comm as BiliPosComment;
                        pos.A1 = a1;
                        pos.A2 = a2;
                        row.Cells[5].Value = pos.Message;
                        ChangeRow(row, true);
                    }
                }, () => {
                    statusMessage.Text = "修改透明度完毕！";
                });
            }
        }
        private void EditPosLife_Click(object sender, EventArgs e) {
            string str = InputForm.ShowInput(this, "输入存活时间（0,10）：", "存活时间");
            if (str != null) {
                float life = float.Parse(str);
                if (life <= 0 || life >= 10) {
                    MessageBox.Show(this, "存活时间不在预期值范围之内！", "更改存活时间",
                        MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }
                EnumSelected((row, n) => {
                    BiliComment comm = _comments[row.Cells[0].Value.ToString()];
                    if (comm is BiliPosComment) {
                        BiliPosComment pos = comm as BiliPosComment;
                        pos.Life = life;
                        row.Cells[5].Value = pos.Message;
                        ChangeRow(row, true);
                    }
                }, () => {
                    statusMessage.Text = "修改存活时间完毕！";
                });
            }
        }
        private void Config_Click(object sender, EventArgs e) {
            ConfigForm cfg = new ConfigForm();
            cfg.ShowDialog(this);
        }
        private void About_Click(object sender, EventArgs e) {
            new AboutForm().ShowDialog(this);
        }

        private void Post_Click(object sender, EventArgs e) {
            if (string.IsNullOrEmpty(toolTextId.Text.Trim())) {
                MessageBox.Show(this, "请填写弹幕池ID！", "VID",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                toolTextId.Focus();
                return;
            }
            if (gridComments.SelectedRows.Count <= 0) {
                MessageBox.Show(this, "请选择要发送的弹幕！", "发送",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            if (MessageBox.Show(this, "是否确认发送？", "发送",
                MessageBoxButtons.YesNo, MessageBoxIcon.Question)
                == System.Windows.Forms.DialogResult.No) {
                statusMessage.Text = "用户取消发送";
                return;
            }
            string vid = toolTextId.Text;
            if (vid.StartsWith("av")) {
                _net.AvToVid(vid, (id) => {
                    this.Invoke((MethodInvoker)delegate {
                        PostExec(id);
                    });
                }, (msg) => {
                    statusMessage.Text = msg;
                });
            } else {
                PostExec(vid);
            }
        }
        private void PostExec(string vid) {
            try {
                int step = (int)(float.Parse(toolTextStep.Text) * 10); // 百毫秒
                int pool = toolComboPool.SelectedIndex; // 弹幕池
                if ((Config.m_Level == Level.Member) && (step < 50)) {
                    MessageBox.Show(this, "普通会员发送间隔不得小于5s，已自动更改为5s",
                        "发送间隔", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    step = 52;
                } else if ((Config.m_Level == Level.Guest) && (step < 100)) {
                    MessageBox.Show(this, "游客发送间隔不得小于10s，已自动更改为10s",
                        "发送间隔", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    step = 102;
                }
                if ((Config.m_Level < Level.Commenter) && (pool != 0)) {
                    MessageBox.Show(this, "字幕君以下会员不能发往字幕池，已改为普通池",
                        "弹幕池", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    pool = 0;
                }
                float offset = float.Parse(toolTextOffset.Text);
                _postState = PostState.Sending;
                EnableToolStrip(false);
                bool first = true;
                Thread poster = null;
                statusProgressBar.Maximum = gridComments.SelectedRows.Count;
                statusProgressBar.Value = 0;
                statusProgressBar.Visible = true;
                for (int i = 0; i < gridComments.Rows.Count; i++) {
                    DataGridViewRow row = gridComments.Rows[i];
                    if (!row.Selected) {
                        continue;
                    }
                    BiliComment comm = _comments[row.Cells[0].Value.ToString()];
                    // 核对权限
                    string err = null;
                    if (Config.m_Level == Level.Guest) {
                        if (err == null && comm.Mode != 1)
                            err = "游客只能发送滚动弹幕！";
                        if (err == null && comm.Fontsize != 25)
                            err = "游客只能发送中号字（25）！";
                    } else if (Config.m_Level == Level.Member) {
                        if (err == null && (comm.Mode == 6 || comm.Mode == 7))
                            err = "普通会员无法发送逆向弹幕和定位弹幕！";
                    }
                    if (err != null) {
                        MessageBox.Show(this, err, "权限错误", MessageBoxButtons.OK,
                            MessageBoxIcon.Warning);
                        row.Cells[4].Value = "×，" + err;
                        statusProgressBar.Value++;
                        continue;
                    }
                    // 延迟
                    if (!first) {
                        for (int t = 0; t < step; t++) {
                            // step百毫秒间隔
                            Thread.Sleep(100);
                            Application.DoEvents();
                            while (_postState == PostState.Paused) {
                                Thread.Sleep(100);
                                Application.DoEvents();
                            }
                            if (_postState == PostState.Stopped
                                || _postState == PostState.Error) {
                                goto endpost;
                            }
                        }
                    } else {
                        first = false;
                    }
                    string data = "date=" + StringUtil.UrlEncode(
                            comm.Date.ToString("yyyy-MM-dd HH:mm:ss"))
                        + "&pool=" + pool
                        + "&message=" + StringUtil.UrlEncode(HttpUtility.UrlEncode(
                            comm.Message.Replace("\r", "").Replace("\n", "/n"),
                            Encoding.UTF8))
                        + "&color=" + comm.Color
                        + "&fontsize=" + comm.Fontsize
                        + "&rnd=" + Utility.Rnd.Next(10000)
                        + "&mode=" + comm.Mode
                        + "&playTime=" + StringUtil.UrlEncode((comm.PlayTime
                            - offset).ToString())
                        + "&vid=" + vid;
                    //MessageBox.Show(data);
                    //continue;

                    byte[] bs = Encoding.ASCII.GetBytes(data);
                    poster = new Thread(str => {
                        string s = str as string;
                        if (string.IsNullOrEmpty(s))
                            return;
                        Http.Connect(Config.m_HttpBase + "/dmpost", (bili) => {
                            bili.Method = "POST";
                            bili.Headers["Cookie"] = Config.m_Cookie;
                            bili.Referer = Config.m_HttpBase + "/PADplayer.swf";
                            bili.ContentType = "application/x-www-form-urlencoded";
                            bili.ContentLength = bs.Length;
                            using (Stream biliStream = bili.GetRequestStream()) {
                                biliStream.Write(bs, 0, bs.Length);
                                biliStream.Close();
                            }
                        }, (bili, response) => {
                            using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) {
                                this.Invoke(new Action<string>(m => {
                                    statusMessage.Text += "，返回：" + m;
                                    row.Cells[4].Value = "√";
                                }), reader.ReadLine());

                                reader.Close();
                                reader.Dispose();
                            }
                        }, (ex) => {
                            this.Invoke(new Action<string>(m => {
                                row.Cells[4].Value = "×，" + ex.Message;
                            }), ex.Message);
                            _postState = PostState.Error;
                        });
                    });
                    poster.Start(data);
                    string remain = "约剩余："
                        + (statusProgressBar.Maximum - statusProgressBar.Value - 1)
                        * (step / 10f) + "秒，";
                    statusMessage.Text = remain + "正在发送ID：" + i + ".请稍候..";
                    int nn = 1;
                    while ((poster != null) && (poster.ThreadState == ThreadState.Running)) {
                        Thread.Sleep(100);
                        if (nn % 2 == 0) {
                            statusMessage.Text += ".";
                        }
                        nn++;
                        Application.DoEvents();
                    }
                    statusProgressBar.Value++;
                }
            // 结束
            endpost:
                if (_postState == PostState.Stopped) {
                    statusMessage.Text += "，弹幕发送被用户终止！";
                } else if (_postState == PostState.Error) {
                    statusMessage.Text += "，弹幕服务器返回错误！";
                    MessageBox.Show(this, "发送过程中服务端返回错误！", "错误",
                        MessageBoxButtons.OK, MessageBoxIcon.Warning);
                } else {
                    statusMessage.Text += "，所有弹幕发送完毕。";
                }
            } catch (Exception ex) {
                MessageBox.Show(this, "发送过程中出现参数错误！Msg: " + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                statusMessage.Text = "参数错误...";
            }
            statusProgressBar.Visible = false;
            _postState = PostState.Stopped;
            EnableToolStrip(true);
        }
        private void Stop_Click(object sender, EventArgs e) {
            _postState = PostState.Paused;
            if (MessageBox.Show(this, "是否确定中断发送？", "中断", MessageBoxButtons.YesNo, MessageBoxIcon.Question)
                == System.Windows.Forms.DialogResult.Yes) {
                _postState = PostState.Stopped;
            } else {
                _postState = PostState.Sending;
            }
        }

        private void Grid_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e) {
            if (e.Button == System.Windows.Forms.MouseButtons.Right
                && gridComments.SelectedRows.Count <= 1) {
                try {
                    gridComments.CurrentCell =
                        gridComments.Rows[e.RowIndex].Cells[e.ColumnIndex];
                } catch { }
            }
        }
        private void Grid_CellEndEdit(object sender, DataGridViewCellEventArgs e) {
            DataGridViewRow row = gridComments.Rows[e.RowIndex];
            BiliComment comm = _comments[row.Cells[0].Value.ToString()];
            object value = row.Cells[e.ColumnIndex].Value;
            if (e.ColumnIndex == 1) {
                // 播放时间
                float playTime = (float)value;
                if (playTime != comm.PlayTime) {
                    comm.PlayTime = playTime;
                    Changed(true);
                    ChangeRow(row, true);
                }
            } else if (e.ColumnIndex == 2) {
                // 颜色
                string cstr = value as string;
                try {
                    int color = StringUtil.IntColorFromString(cstr);
                    if (color != comm.Color) {
                        comm.Color = color;
                        Changed(true);
                        ChangeRow(row, true);
                    }
                } catch (Exception ex) {
                    MessageBox.Show(this, ex.Message, "颜色",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                    row.Cells[2].Value = StringUtil.StringFromColorInt(comm.Color);
                }
            } else if (e.ColumnIndex == 3) {
                // 字号
                int fontsize = (int)value;
                if (fontsize != comm.Fontsize) {
                    comm.Fontsize = fontsize;
                    Changed(true);
                    ChangeRow(row, true);
                }
            } else if (e.ColumnIndex == 5) {
                // 弹幕内容
                string msg = value as string;
                if (msg != comm.Message) {
                    try {
                        comm.Message = msg;
                        Changed(true);
                        ChangeRow(row, true);
                    } catch (Exception ex) {
                        MessageBox.Show(this, ex.Message, "内容",
                            MessageBoxButtons.OK, MessageBoxIcon.Error);
                        row.Cells[5].Value = comm.Message;
                    }
                }
            }
        }
        private void Grid_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) {
            if (e.ColumnIndex == 5) {
                // 弹幕内容
                IntPtr hIme = NativeMethods.ImmGetContext(gridComments.Handle);
                if (!NativeMethods.ImmGetOpenStatus(hIme)) {
                    NativeMethods.ImmSetOpenStatus(hIme, true);
                }
            } else {
                // 其他
                IntPtr hIme = NativeMethods.ImmGetContext(gridComments.Handle);
                if (NativeMethods.ImmGetOpenStatus(hIme)) {
                    NativeMethods.ImmSetOpenStatus(hIme, false);
                }
            }
        }
        private void Grid_DataError(object sender, DataGridViewDataErrorEventArgs e) {
            e.Cancel = true;
            if (e.ColumnIndex == 1) {
                MessageBox.Show(this, "播放时间格式不正确！", "时间",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
            } else if (e.ColumnIndex == 3) {
                MessageBox.Show(this, "字号必须是整数！", "字号",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }
        private void Grid_DragEnter(object sender, DragEventArgs e) {
            if (e.Data.GetDataPresent(DataFormats.FileDrop)) {
                string file = ((string[])e.Data.GetData(DataFormats.FileDrop))[0].ToLower();
                if (file.EndsWith(".xml")) {
                    e.Effect = DragDropEffects.Copy;
                }
            }
        }
        private void Grid_DragDrop(object sender, DragEventArgs e) {
            string file = ((string[])e.Data.GetData(DataFormats.FileDrop))[0];
            OpenFile(file);
        }
        private void Grid_SelectionChanged(object sender, EventArgs e) {
            if (gridComments.SelectedRows.Count <= 0)
                return;
            _selected = new int[gridComments.SelectedRows.Count];
            int i = 0;
            foreach (DataGridViewRow row in gridComments.SelectedRows) {
                _selected[i++] = int.Parse(row.Cells[0].Value.ToString());
            }
        }
        private void Grid_KeyUp(object sender, KeyEventArgs e) {
            if (e.Modifiers == Keys.Control && e.KeyCode == Keys.C) {
                menuCopy.PerformClick();
            } else if (e.Modifiers == Keys.Control && e.KeyCode == Keys.V) {
                menuPaste.PerformClick();
                //} else if (e.Modifiers == Keys.Control && e.KeyCode == Keys.B) {
                //    menuPasteEdit.PerformClick();
            } else if (e.KeyData == Config.m_Edit) {
                menuEdit.PerformClick();
            } else if (e.Modifiers == Keys.None && e.KeyCode == Keys.Delete) {
                if (gridComments.SelectedRows.Count > 0) {
                    if (MessageBox.Show(this, "是否确定删除？", "删除弹幕",
                        MessageBoxButtons.YesNo, MessageBoxIcon.Question)
                        == System.Windows.Forms.DialogResult.Yes) {
                        menuDelete.PerformClick();
                    }
                }
            } else {
                DataGridViewRow row = gridComments.CurrentRow;
                if (row == null)
                    return;
                if (e.KeyData == Config.m_EditTime) {
                    gridComments.CurrentCell = row.Cells[1];
                    gridComments.BeginEdit(true);
                } else if (e.KeyData == Config.m_EditColor) {
                    gridComments.CurrentCell = row.Cells[2];
                    gridComments.BeginEdit(true);
                } else if (e.KeyData == Config.m_EditSize) {
                    gridComments.CurrentCell = row.Cells[3];
                    gridComments.BeginEdit(true);
                } else if (e.KeyData == Config.m_EditMsg) {
                    gridComments.CurrentCell = row.Cells[5];
                    gridComments.BeginEdit(true);
                }
            }
        }
        private void Grid_KeyDown(object sender, KeyEventArgs e) {
            if (e.Modifiers == Keys.Control) {
                if (e.KeyCode == Keys.Up) {
                    MoveUp_Click(null, null);
                    e.Handled = true;
                } else if (e.KeyCode == Keys.Down) {
                    MoveDown_Click(null, null);
                    e.Handled = true;
                }
            }
        }
        private void Grid_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) {
        }
    }
}
